package com.learning.algorithm.service;

import com.learning.algorithm.Word;
import com.learning.algorithm.model.Person;
import com.learning.algorithm.model.SimilarInputParam;
import com.learning.algorithm.model.SimilarResult;
import com.learning.algorithm.model.Unit;
import com.learning.algorithm.util.SegmentationUtil;
import com.learning.algorithm.util.SimilarityUtil;
import com.learning.algorithm.util.TransferUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: daqian_liao
 * @Date: 2018/12/12 19:57
 * @Version 1.0
 */
@Log4j2
@Service("similarService")
public class SimilarService {


    public static SimilarResult get(SimilarInputParam params){
        SimilarResult result  = new SimilarResult();
        Map<String, List<Word>> map = getMap(params.getVoiceText());

        //人员
        List<Person> persons = new ArrayList<Person>();
        for (Person p:params.getProjectPersonnels()){
            p.setMatch(0.0);
            p.setMatch(match(map,p.getName()));
        }
        params.getProjectPersonnels().sort((o1, o2) -> o2.getMatch().compareTo(o1.getMatch()));

        if (params.getProjectPersonnels().size()>2){
            persons.add(params.getProjectPersonnels().get(0));
            persons.add(params.getProjectPersonnels().get(1));
            persons.add(params.getProjectPersonnels().get(2));
        }else if (params.getProjectPersonnels().size()>1){
            persons.add(params.getProjectPersonnels().get(0));
            persons.add(params.getProjectPersonnels().get(1));
        } else if(params.getProjectPersonnels().size()>0){
            persons.add(params.getProjectPersonnels().get(0));
        }

        //单位
        List<Unit> units = new ArrayList<Unit>();
        for (Unit u:params.getSubcontractingUnits()){
            u.setMatch(0.0);
            u.setMatch(match(map,u.getName()));
        }
        params.getSubcontractingUnits().sort((o1, o2) -> o2.getMatch().compareTo(o1.getMatch()));

        if (params.getSubcontractingUnits().size()>2){
            units.add(params.getSubcontractingUnits().get(0));
            units.add(params.getSubcontractingUnits().get(1));
            units.add(params.getSubcontractingUnits().get(2));
        }else if (params.getSubcontractingUnits().size()>1){
            units.add(params.getSubcontractingUnits().get(0));
            units.add(params.getSubcontractingUnits().get(1));
        } else if(params.getSubcontractingUnits().size()>0){
            units.add(params.getSubcontractingUnits().get(0));
        }

        result.setPersons(persons);
        result.setUnits(units);
        return result;
    }


    public static Map<String, Double> match(String text, List<String> keys) {
        Map<String, Double> score = new HashMap<>();
        Map<String, List<Word>> map = getMap(text);
        System.out.println("text map = " + map);
        keys.stream().forEach(x -> score.put(x, match(map, x)));

        Map<String, Double> sortScore = new LinkedHashMap<>();
        score.entrySet().stream().sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue()))
                .forEach(entry -> sortScore.put(entry.getKey(), entry.getValue()));
        System.out.println("score map = " + sortScore);
        return sortScore;
    }

    public static double match(Map<String, List<Word>> map, String key) {
        double directMatch = directMatch(map, new Word(key));
        double accentsMatch = accentsMatch(map, new Word(key));
        return Math.max(directMatch, accentsMatch);
    }

    public static double match(String text, String key) {
        Map<String, List<Word>> map = getMap(text);
        return match(map, key);
    }

    public static double directMatch(Map<String, List<Word>> map, Word key) {
        double score = 0;
        List<Word> words = map.get(key.getFirstLetterPy());

        if (words != null && !words.isEmpty()) {
            List<String> collect = words.stream().map(x -> x.getChinese() + x.getPinyin())
                    .collect(Collectors.toList());
            score = mutilAlgo(collect, key.getChinese() + key.getPinyin(), 0.5, 0.5);
        }
        return score;
    }

    public static double accentsMatch(Map<String, List<Word>> map, Word key) {
        double score = 0;
        List<Word> words = map.get(TransferUtil.accentTransfer(key.getFirstLetterPy()));
        if (words != null && !words.isEmpty()) {
            List<String> accents = words.stream().map(Word::getPinyin)
                    .collect(Collectors.toList());
            score = mutilAlgo(accents, TransferUtil.accentTransfer(key.getPinyin()), 0.5, 0.5);
        }
        return score;
    }

    private static Map<String, List<Word>> getMap(String text) {
        List<String> splitWords = SegmentationUtil.getSplitWords(text);
        splitWords.addAll(TransferUtil.mergeSingle(splitWords));
        List<Word> words = splitWords.stream()
                .map(Word::new).collect(Collectors.toList());
        Map<String, List<Word>> map = new HashMap<>(32);
        for (Word word : words) {
            if (map.containsKey(word.getFirstLetterPy())) {
                List<Word> words1 = map.get(word.getFirstLetterPy());
                words1.add(word);
                map.put(word.getFirstLetterPy(), words1);
            } else {
                List<Word> words1 = new ArrayList<>();
                words1.add(word);
                map.put(word.getFirstLetterPy(), words1);
            }
        }
        return map;
    }

    public static double mutilAlgo(List<String> str1s, String str2, double rate1, double rate2) {
        return str1s.stream().mapToDouble(x -> mutilAlgo(x, str2, rate1, rate2)).max().getAsDouble();
    }

    public static double mutilAlgo(String str1, String str2, double rate1, double rate2) {
        return algoCosDistinct(str1, str2) * rate1 + rate2 * algoLevenshtein(str1, str2);
    }

    public static double algoCosDistinct(String str1, String str2) {
        return SimilarityUtil.getSimilarity(str1, str2);
    }

    public static double algoLevenshtein(String str1, String str2) {
        return SimilarityUtil.levenshtein(str1, str2);
    }

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
//        match("18号楼15层消防连廊处未搭设临边防护，存在高空坠落风险，张三,李四应督促深圳蒹葭劳务公司马上整改，逾期未整改将按照合同规定进行处罚","张三");
//        match("18号楼15层消防连廊处未搭设临边防护，存在高空坠落风险，张三,李四应督促深圳蒹葭劳务公司马上整改，逾期未整改将按照合同规定进行处罚","李四");
//        match("18号楼15层消防连廊处未搭设临边防护，存在高空坠落风险，张三应督促深圳蒹葭劳务公司马上整改，逾期未整改将按照合同规定进行处罚", "章三");
//
//        match("18号楼15层消防连廊处未搭设临边防护，存在高空坠落风险，张三疯应督促深圳蒹葭劳务公司马上整改，逾期未整改将按照合同规定进行处罚", "张三丰");
//        match("18号楼15层消防连廊处未搭设临边防护，存在高空坠落风险，牛红应督促深圳桃夭劳务公司马上整改，逾期未整改将按照合同规定进行处罚", "刘红");
//        match("18号楼15层消防连廊处未搭设临边防护，存在高空坠落风险，服北应督促深圳桃夭劳务公司马上整改，逾期未整改将按照合同规定进行处罚", "湖北");
//

        List<String> keys = new ArrayList<>();
        keys.add("张三丰");
        keys.add("刘红");
        keys.add("胡四索");
        match("18号楼15层消防连廊处未搭设临边防护，存在高空坠落风险，张三疯应督促深圳桃夭劳务公司马上整改，逾期未整改将按照合同规定进行处罚", keys);
        match("18号楼15层消防连廊处未搭设临边防护，存在高空坠落风险，牛红应督促深圳桃夭劳务公司马上整改，逾期未整改将按照合同规定进行处罚", keys);
        match("18号楼15层消防连廊处未搭设临边防护，存在高空坠落风险，福司索应督促深圳桃夭劳务公司马上整改，逾期未整改将按照合同规定进行处罚", keys);

        long end = System.currentTimeMillis();
        log.info("took = {}ms", end - startTime);
    }

}
